package com.cy.stone.framework.satoken;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONUtil;
import com.cy.stone.framework.redis.RedisKey;
import com.cy.stone.framework.redis.RedisUtil;
import com.cy.stone.system.application.RoleMenuApi;
import com.cy.stone.system.infrastructure.database.entity.UserRoleEntity;
import com.cy.stone.system.infrastructure.database.service.IUserRoleService;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.cy.stone.system.infrastructure.database.table.UserRoleTableDef.USER_ROLE_ENTITY;


/**
 * 自定义权限加载接口实现类
 * @author Wings
 * @since 2023-12-09
 */
@Component
@RequiredArgsConstructor
public class StpInterfaceImpl implements StpInterface {

    private final IUserRoleService userRoleService;

    private final RoleMenuApi roleMenuApi;

    /**
     * 返回一个账号所拥有的权限码集合
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 1. 声明权限码集合
        List<String> permissionList = new ArrayList<>();
        // 2. 遍历角色列表，查询拥有的权限码
        for (String roleCode : getRoleList(loginId, loginType)) {
            if (RedisUtil.hasKey(RedisKey.ROLE_KEY + roleCode)) {
                String result = RedisUtil.getCacheObject(RedisKey.ROLE_KEY + roleCode);
                List<String> list = JSONUtil.toList(result, String.class);
                permissionList.addAll(list);
            } else {
                List<String> list = roleMenuApi.cachePermission(roleCode);
                permissionList.addAll(list);
            }
        }
        // 3. 返回权限码集合
        return permissionList.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        SaSession session = StpUtil.getSessionByLoginId(loginId);
        return session.get(SaSession.ROLE_LIST, () -> {
            List<UserRoleEntity> list = userRoleService.list(QueryWrapper.create().from(USER_ROLE_ENTITY)
                    .where(USER_ROLE_ENTITY.USER_NAME.eq(loginId.toString())));
            return list.stream().map(UserRoleEntity::getRoleCode).collect(Collectors.toList());
        });
    }
}
